from datetime import datetime
from sqlalchemy.orm import relationship, Mapped, mapped_column
from core.database import BaseModel, Base
from sqlalchemy import String, Boolean, DateTime, SmallInteger, Integer, ForeignKey, Column, Table
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')

sys_user_role = Table(
    "sys_user_role",
    Base.metadata,
    Column("user_id", Integer, ForeignKey("sys_user.id", ondelete="CASCADE")),
    Column("role_id", Integer, ForeignKey("sys_role.id", ondelete="CASCADE")),
)

sys_role_menu = Table(
    "sys_role_menu",
    Base.metadata,
    Column("role_id", Integer, ForeignKey("sys_role.id", ondelete="CASCADE")),
    Column("menu_id", Integer, ForeignKey("sys_menu.id", ondelete="CASCADE")),
)

sys_user_dept = Table(
    "sys_user_dept",
    Base.metadata,
    Column("user_id", Integer, ForeignKey("sys_user.id", ondelete="CASCADE")),
    Column("dept_id", Integer, ForeignKey("sys_dept.id", ondelete="CASCADE")),
)

sys_role_dept = Table(
    "sys_role_dept",
    Base.metadata,
    Column("role_id", Integer, ForeignKey("sys_role.id", ondelete="CASCADE")),
    Column("dept_id", Integer, ForeignKey("sys_dept.id", ondelete="CASCADE")),
)


class SysDept(BaseModel):
    __tablename__ = "sys_dept"
    __table_args__ = ({'comment': '部门表'})

    name: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="部门名称")
    dept_key: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="部门标识")
    disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
    order: Mapped[int | None] = mapped_column(Integer, comment="显示排序")
    desc: Mapped[str | None] = mapped_column(String(255), comment="描述")
    owner: Mapped[str | None] = mapped_column(String(255), comment="负责人")
    phone: Mapped[str | None] = mapped_column(String(255), comment="联系电话")
    email: Mapped[str | None] = mapped_column(String(255), comment="邮箱")

    parent_id: Mapped[int | None] = mapped_column(
        Integer, ForeignKey("sys_dept.id", ondelete='CASCADE'), comment="上级部门"
    )


class SysMenu(BaseModel):
    __tablename__ = "sys_menu"
    __table_args__ = ({'comment': '菜单表'})

    title: Mapped[str] = mapped_column(String(50), comment="名称")
    icon: Mapped[str | None] = mapped_column(String(50), comment="菜单图标")
    redirect: Mapped[str | None] = mapped_column(String(100), comment="重定向地址")
    component: Mapped[str | None] = mapped_column(String(255), comment="前端组件地址")
    path: Mapped[str | None] = mapped_column(String(50), comment="前端路由地址")
    activeMenu: Mapped[str | None] = mapped_column(String(50), comment="当路由设置了该属性，则会高亮相对应的侧边栏.")
    disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
    hidden: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否隐藏")
    order: Mapped[int] = mapped_column(Integer, comment="排序")
    menu_type: Mapped[str] = mapped_column(String(8), comment="菜单类型")
    parent_id: Mapped[int | None] = mapped_column(
        Integer,
        ForeignKey("sys_menu.id", ondelete='CASCADE'),
        comment="父菜单"
    )
    perms: Mapped[str | None] = mapped_column(String(50), comment="权限标识", unique=False, index=True)

    """以下属性主要用于补全前端路由属性，"""
    noCache: Mapped[bool] = mapped_column(
        Boolean,
        comment="如果设置为true，则不会被 <keep-alive> 缓存(默认 false)",
        default=False
    )
    breadcrumb: Mapped[bool] = mapped_column(
        Boolean,
        comment="如果设置为false，则不会在breadcrumb面包屑中显示(默认 true)",
        default=True
    )
    affix: Mapped[bool] = mapped_column(
        Boolean,
        comment="如果设置为true，则会一直固定在tag项中(默认 false)",
        default=False
    )
    noTagsView: Mapped[bool] = mapped_column(
        Boolean,
        comment="如果设置为true，则不会出现在tag中(默认 false)",
        default=False
    )
    canTo: Mapped[bool] = mapped_column(
        Boolean,
        comment="设置为true即使hidden为true，也依然可以进行路由跳转(默认 false)",
        default=False
    )
    alwaysShow: Mapped[bool] = mapped_column(
        Boolean,
        comment="""当你一个路由下面的 children 声明的路由大于1个时，自动会变成嵌套的模式，
    只有一个时，会将那个子路由当做根路由显示在侧边栏，若你想不管路由下面的 children 声明的个数都显示你的根路由，
    你可以设置 alwaysShow: true，这样它就会忽略之前定义的规则，一直显示根路由(默认 true)""",
        default=True
    )


class SysRole(BaseModel):
    __tablename__ = "sys_role"
    __table_args__ = ({'comment': '角色表'})

    name: Mapped[str] = mapped_column(String(50), index=True, comment="名称")
    role_key: Mapped[str] = mapped_column(String(50), index=True, comment="权限字符")
    data_range: Mapped[int] = mapped_column(Integer, default=4, comment="数据权限范围")
    disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
    order: Mapped[int | None] = mapped_column(Integer, comment="排序")
    desc: Mapped[str | None] = mapped_column(String(255), comment="描述")
    is_admin: Mapped[bool] = mapped_column(Boolean, comment="是否为超级角色", default=False)

    menus: Mapped[set[SysMenu]] = relationship(secondary=sys_role_menu)
    depts: Mapped[set[SysDept]] = relationship(secondary=sys_role_dept)


class SysUser(BaseModel):
    __tablename__ = "sys_user"
    __table_args__ = ({'comment': '用户表'})

    username: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="账号")
    name: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="姓名")
    password: Mapped[str] = mapped_column(String(255), nullable=True, comment="密码")
    avatar: Mapped[str | None] = mapped_column(String(500), comment='头像')
    email: Mapped[str | None] = mapped_column(String(50), comment="邮箱地址")
    telephone: Mapped[str] = mapped_column(String(11), nullable=True, comment="手机号", unique=False)
    gender: Mapped[str | None] = mapped_column(SmallInteger, nullable=True, comment="性别，0:男 1:女")
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, comment="是否可用")
    last_ip: Mapped[str | None] = mapped_column(String(50), comment="最后一次登录IP")
    last_login: Mapped[datetime | None] = mapped_column(DateTime, comment="最近一次登录时间")

    roles: Mapped[set[SysRole]] = relationship(secondary=sys_user_role)
    depts: Mapped[set[SysDept]] = relationship(secondary=sys_user_dept)

    @staticmethod
    def get_password_hash(password: str) -> str:
        """
        生成哈希密码
        :param password: 原始密码
        :return: 哈希密码
        """
        return pwd_context.hash(password)

    @staticmethod
    def verify_password(password: str, hashed_password: str) -> bool:
        """
        验证原始密码是否与哈希密码一致
        :param password: 原始密码
        :param hashed_password: 哈希密码
        :return:
        """
        return pwd_context.verify(password, hashed_password)

    def is_admin(self) -> bool:
        """
        获取该用户是否拥有最高权限
        以最高权限为准
        :return:
        """
        return any([i.is_admin for i in self.roles])


class SysDict(BaseModel):
    __tablename__ = "sys_dict"
    __table_args__ = ({'comment': '字典类型表'})

    name: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="字典名称")
    code: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="字典类型")
    disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="字典状态，是否禁用")
    desc: Mapped[str | None] = mapped_column(String(255), comment="描述")
    details: Mapped[list["SysDictDetail"]] = relationship(back_populates="dict")


class SysDictDetail(BaseModel):
    __tablename__ = "sys_dict_detail"
    __table_args__ = ({'comment': '字典详情表'})

    label: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="字典标签")
    value: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="字典键值")
    disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="字典状态，是否禁用")
    order: Mapped[int] = mapped_column(Integer, comment="字典排序")
    dict_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_dict.id", ondelete='CASCADE'),
        comment="关联字典类型"
    )
    dict: Mapped[SysDict] = relationship(foreign_keys=dict_id, back_populates="details")


class SysVersion(BaseModel):
    __tablename__ = "sys_version"
    __table_args__ = ({'comment': '版本表'})

    name: Mapped[str] = mapped_column(String(50), nullable=False, comment="版本")
    start_time: Mapped[datetime | None] = mapped_column(DateTime, comment='开始时间')
    end_time: Mapped[datetime | None] = mapped_column(DateTime, comment='结束时间')
    order: Mapped[int] = mapped_column(Integer, comment="排序，数字越大说明版本越大")
    disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="版本状态，是否禁用")
    desc: Mapped[str | None] = mapped_column(String(255), comment="描述")


class PublicCatalog(BaseModel):
    __tablename__ = "public_catalog"
    __table_args__ = ({'comment': '公共目录表'})

    name: Mapped[str] = mapped_column(String(50), nullable=False, comment="目录名称")
    order: Mapped[int | None] = mapped_column(Integer, comment="排序")
    catalog_type: Mapped[int] = mapped_column(Integer, nullable=False, comment="目录类型，0:功能测试用例")
    related_id: Mapped[int | None] = mapped_column(
        Integer, comment="相关Id，多个目录树的时候使用，比如:每个用例库都有一个目录，那么就需要catalog_type和related_id结合使用"
    )
    parent_id: Mapped[int | None] = mapped_column(
        Integer,
        ForeignKey("public_catalog.id", ondelete='RESTRICT'),
        comment="父级id"
    )


functional_caselib_follow = Table(
    "functional_caselib_follow",
    Base.metadata,
    Column("user_id", Integer, ForeignKey("sys_user.id", ondelete="CASCADE")),
    Column("caselib_id", Integer, ForeignKey("functional_caselib.id", ondelete="CASCADE"))
)


class FunctionalCaselib(BaseModel):
    __tablename__ = "functional_caselib"
    __table_args__ = ({'comment': '测试用例库表'})

    name: Mapped[str] = mapped_column(String(50), index=True, nullable=False, comment="用例库名称")
    desc: Mapped[str | None] = mapped_column(String(200), comment="描述")
    create_user_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_user.id", ondelete='RESTRICT'),
        comment="创建人"
    )
    create_user: Mapped[SysUser] = relationship(foreign_keys=create_user_id)
    users: Mapped[set[SysUser]] = relationship(secondary=functional_caselib_follow)


class FunctionalTestcase(BaseModel):
    __tablename__ = "functional_testcase"
    __table_args__ = ({'comment': '测试用例表'})

    title: Mapped[str] = mapped_column(String(200), index=True, nullable=False, comment="用例标题")
    level: Mapped[str] = mapped_column(String(10), nullable=False, comment="用例等级")
    desc: Mapped[str | None] = mapped_column(String(200), comment="描述")
    status: Mapped[int] = mapped_column(Integer, default=0, comment="状态， 0:进行中 1:已完成 2:已废弃")
    precondition: Mapped[str | None] = mapped_column(String(200), comment="前置条件")
    version_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_version.id", ondelete="RESTRICT"),
        comment="当前版本id"
    )
    max_version_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_version.id", ondelete="RESTRICT"),
        comment="最高版本id"
    )
    caselib_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("functional_caselib.id", ondelete="CASCADE"),
        comment="用例库id"
    )
    catalog_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("public_catalog.id", ondelete="RESTRICT"),
        comment="目录id"
    )
    create_user_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_user.id", ondelete="RESTRICT"),
        comment="创建人"
    )
    update_user_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_user.id", ondelete="RESTRICT"),
        comment="更新人"
    )
    version: Mapped[SysVersion] = relationship(foreign_keys=version_id)
    max_version: Mapped[SysVersion] = relationship(foreign_keys=max_version_id)
    create_user: Mapped[SysUser] = relationship(foreign_keys=create_user_id)
    update_user: Mapped[SysUser] = relationship(foreign_keys=update_user_id)
    steps: Mapped[set["FunctionalTestcaseStep"]] = relationship(back_populates="testcase")


class FunctionalTestcaseStep(BaseModel):
    __tablename__ = "functional_testcase_step"
    __table_args__ = ({'comment': '测试用例步骤表'})

    num: Mapped[int] = mapped_column(Integer, comment="步骤序号")
    action: Mapped[str] = mapped_column(String(1000), comment="执行步骤")
    expect: Mapped[str] = mapped_column(String(1000), comment="预期结果")
    remark: Mapped[str | None] = mapped_column(String(200), comment="备注")

    version_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("sys_version.id", ondelete="RESTRICT"),
        comment="版本id"
    )
    testcase_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("functional_testcase.id", ondelete="CASCADE"),
        comment="用例id"
    )
    testcase: Mapped[FunctionalTestcase] = relationship(foreign_keys=testcase_id, back_populates="steps")


# class FunctionalCaseReview(BaseModel):
#     __tablename__ = "functional_case_review"
#     __table_args__ = ({'comment': '用例评审表'})
#
#
# class FunctionalTestPlan(BaseModel):
#     __tablename__ = "functional_test_plan"
#     __table_args__ = ({'comment': '测试计划表'})
#
#     name: Mapped[str] = mapped_column(String(50), nullable=False, comment="计划名称")
#     version_id: Mapped[int] = mapped_column(
#             Integer,
#             ForeignKey("sys_version.id", ondelete="RESTRICT"),
#             comment="版本id"
#         )
#     create_user: Mapped[int] = mapped_column(
#         Integer,
#         ForeignKey("sys_user.id", ondelete="SET_DEFAULT"),
#         default=1,
#         comment="创建人"
#     )
#     executor: Mapped[int] = mapped_column(
#         Integer,
#         ForeignKey("sys_user.id", ondelete="RESTRICT"),
#         comment="执行人"
#     )


# class FunctionalTestPlanDetail(BaseModel):
#     __tablename__ = "functional_test_plan_detail"
#     __table_args__ = ({'comment': '测试计划详细表'})
#
#     result: Mapped[int] = mapped_column(Integer, nullable=False, comment="执行结果, 0:通过 1:未通过 2:跳过 3:阻塞")
#     result_detail: Mapped[str] = mapped_column(TEXT, comment="详细步骤的执行结果，备注")
#     testcase_id: Mapped[int] = mapped_column(
#         Integer,
#         ForeignKey("functional_case.id", ondelete="CASCADE"),
#         comment="用例id"
#     )
